using System;
using System.Collections;
using System.Windows.Forms;
using EasyProjects.ClientModel.Entities;
using System.Collections.Generic;

namespace EasyProjects.TimeLogger
{
    /// <summary>
    /// Main Form
    /// </summary>
    public partial class MainForm : Form
    {
        #region Fields
        private bool isNeedClose;

        /// <summary>
        /// If value is true application close main form and exit. If value is false we should just hide current form.
        /// </summary>
        public bool IsNeedClose
        {
            get { return isNeedClose; }
            set { isNeedClose = value; }
        }

        private SettingsForm sform = new SettingsForm();

        private static SplashForm splashForm = null;

        /// <summary>
        /// Get or set splash form instance. Used for cross-thread using.
        /// </summary>
        public static SplashForm SplashForm
        {
            get { return splashForm; }
            set { splashForm = value; }
        }

        private readonly TaskTimer taskTimer = new TaskTimer();

        private bool isApplicationStarted = false;
        #endregion

        #region Cosntructor

        public MainForm()
        {
            InitializeComponent();
            //set new event hadlers for async update UI during retrieve data from server
            ObjectsHelper.Instance.DataUpdated += new ObjectsHelper.DataUpdatedHandler(Instance_DataUpdated);
            ObjectsHelper.Instance.DataUpdating += new ObjectsHelper.DataUpdatingHandler(Instance_DataUpdating);
            dtDate.Value = DateTime.Today;
        }

        #endregion

        #region ObjectsHelper Handlers
        /// <summary>
        /// Handles the DataUpdating event of the Instance control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Instance_DataUpdating(object sender, EventArgs e)
        {
            //update UI 
            ChangeMainContentVisibility(false);
        }
        /// <summary>
        /// Handles the DataUpdated event of the Instance control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Instance_DataUpdated(object sender, EventArgs e)
        {
            //Recreate all data in comboboxes
            ShowMainContent();
            HideApplicationSplashScreen();
        }
        #endregion

        #region MainForm Handlers FormClosing/Load/VisibleChanged/Shown/FormClosed

        /// <summary>
        /// Handles the VisibleChanged event of the MainForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void MainForm_VisibleChanged(object sender, EventArgs e)
        {
            if (Visible)
                SetPosition();
        }
        /// <summary>
        /// Handles the FormClosing event of the MainForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.FormClosingEventArgs"/> instance containing the event data.</param>
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = !isNeedClose;

            if (e.Cancel) //hide window if close button clicked;
            {
                Hide();
                ShowInTaskbar = false;
            }
            else
            {
                Hide();
                ShowInTaskbar = false;
                Properties.Settings.Default.Save();
            }
        }

        /// <summary>
        /// Handles the Load event of the MainForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(Properties.Settings.Default.EasyProjectsApiUrl)) // if settings filled update data from server
                ObjectsHelper.Instance.Update();
            else//show settings form 
            {
                using (var sform = new SettingsForm())
                {
                    Close();
                    if (sform.ShowDialog() == DialogResult.Cancel)
                    {
                        ShowMainContent();
                        HideApplicationSplashScreen();
                    }
                }
            }
            notifyIcon1.Visible = true;
        }

        /// <summary>
        /// Handles the Shown event of the MainForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void MainForm_Shown(object sender, EventArgs e)
        {
            //hide application main form (just wen application started)
            if (!isApplicationStarted)
            {
                Close();
                isApplicationStarted = true;
            }
        }

        /// <summary>
        /// Vote for my mega programm on application closed.
        /// </summary>
        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            //Prevent displying these forms on screen
            if (sform != null)
                sform.Close();
        }
        #endregion

        #region ToolStripMenu Handles
        /// <summary>
        /// Handles the Click event of the exitToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (taskTimer.Status != TimerStatus.Stopped)
            {
                //notify user about started timer
                if (
                    MessageBox.Show(Strings.TimerStarted, Strings.ApplicationName, MessageBoxButtons.YesNo,
                                    MessageBoxIcon.Warning) == DialogResult.No)
                    return;
            }

            isNeedClose = true;
            Close();
        }

        /// <summary>
        /// Handles the Click event of the showHideToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void showHideToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //show/hide main window
            Visible = !Visible;
            ShowInTaskbar = Visible;
            if (sform != null)//is setting shown close window
                sform.Close();
        }

        /// <summary>
        /// Handles the Click event of the settingsToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //show setting form and close all other windows
            if (sform.Visible)
                return;
            sform = new SettingsForm();
            Close();
            sform.Visible = true;
        }

        /// <summary>
        /// Handles the Click event of the toolStripMenuItem2 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            //show log form
            Close();
            if (sform != null)
                sform.Close();
        }

        /// <summary>
        /// Handles the Click event of the toolStripMenuItem3 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void toolStripMenuItem3_Click(object sender, EventArgs e)
        {
            //retrieve new data from server
            ObjectsHelper.Instance.Update();
        }

        /// <summary>
        /// Handles the Click event of the aboutToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //show about screen
            Close();
            splashForm = new SplashForm();
            splashForm.IsNeedClose = true;
            splashForm.Show();
        }

        /// <summary>
        /// Handles the Click event of the pauseTimerToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pauseTimerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //pause task timer
            taskTimer.Pause();
            UpdateUI();
        }
        #endregion

        #region Buttons Handlres btnStart/btnStop/btnSend/btnClear/btnPause
        /// <summary>
        /// Handles the Click event of the btnStart control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            //start timer
            taskTimer.Start(cbProject.SelectedItem as Project, cbTask.SelectedItem as Task);
            UpdateUI();
        }

        /// <summary>
        /// Handles the Click event of the btnStop control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnStop_Click(object sender, EventArgs e)
        {
            //stop task timer/ update controls for selected project/task
            cbProject.SelectedItem = taskTimer.Project;
            CreateTaskItems();
            cbTask.SelectedItem = taskTimer.Task;
            taskTimer.Stop();
            float hours = taskTimer.Ticks / 3600 + ((float)((taskTimer.Ticks / 60) % 60 * 10 / 6) / 100); // calculate fractal hours notation from seconds notation.
            tbHours.Text = String.Format("{0:F}", hours.ToString());
            UpdateUI();
        }

        /// <summary>
        /// Handles the Click event of the btnClear control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnClear_Click(object sender, EventArgs e)
        {
            //clear filled controls
            ClearData();
        }

        /// <summary>
        /// Handles the Click event of the btnSend control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            //send values on Ep server
            if (!ValidateInput(true))
                return;
            this.Cursor = Cursors.WaitCursor;
            Application.DoEvents();
            try
            {
                if (
                    ObjectsHelper.Instance.SaveEntry((Project)cbProject.SelectedItem, (Task)cbTask.SelectedItem,
                                                     tbDescription.Text,
                                                     dtDate.Value, float.Parse(tbHours.Text), cbBillable.Checked))
                    ClearData();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Strings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            this.Cursor = Cursors.Arrow;
            Application.DoEvents();

        }

        /// <summary>
        /// Handles the Click event of the btnPause control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnPause_Click(object sender, EventArgs e)
        {
            //pause task timer
            taskTimer.Pause();
            UpdateUI();
        }
        #endregion

        #region Controls Hanlers cbTask/tbHours/tbDescription
        /// <summary>
        /// Handles the SelectionChangeCommitted event of the cbTask control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void cbTask_SelectionChangeCommitted(object sender, EventArgs e)
        {
            UpdateUI();
        }

        /// <summary>
        /// Handles the TextChanged event of the tbHours control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tbHours_TextChanged(object sender, EventArgs e)
        {
            UpdateUI();

        }

        /// <summary>
        /// Handles the TextChanged event of the tbDescription control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tbDescription_TextChanged(object sender, EventArgs e)
        {
            UpdateUI();
        }

        /// <summary>
        /// Handles the SelectionChangeCommitted event of the cbProject control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void cbProject_SelectionChangeCommitted(object sender, EventArgs e)
        {
            //create tasks list
            CreateTaskItems();
            UpdateUI();
        }
        #endregion

        #region Timmer
        /// <summary>
        /// Handles the Tick event of the timer1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            //increment task timer and pdate UI text
            taskTimer.Tick();
            lbTime.Text = taskTimer.DisplayTime;

            notifyIcon1.Text = String.Format(Strings.TimeSpended, taskTimer.DisplayTime);
        }

        #endregion

        #region Help methods
        /// <summary>
        /// Clear all entered data.
        /// </summary>
        private void ClearData()
        {
            tbHours.Text = String.Empty;
            tbDescription.Text = String.Empty;
            cbBillable.Checked = true;
        }

        /// <summary>
        /// Create tasks list and select first item if exist.
        /// </summary>
        private void CreateTaskItems()
        {
            cbTask.Items.Clear();
            var tasks = ObjectsHelper.Instance.TasksByProject(cbProject.SelectedItem as Project);
            foreach (Task o in tasks)
                cbTask.Items.Add(o);
            if (cbTask.Items.Count > 0)
                cbTask.SelectedIndex = 0;
        }

        /// <summary>
        /// Update UI. Set enable/disable for buttons and other controls.
        /// </summary>
        private void UpdateUI()
        {
            btnSend.Enabled = ValidateInput(false);

            //set enable/disable for timer buttons.
            startTimerToolStripMenuItem1.Enabled =
                btnStart.Enabled =
                (taskTimer.Status == TimerStatus.Stopped) && (cbProject.SelectedItem != null) &&
                (cbTask.SelectedItem != null);
            stopTimerToolStripMenuItem.Enabled = btnStop.Enabled = taskTimer.Status != TimerStatus.Stopped;
            pauseTimerToolStripMenuItem.Enabled = btnPause.Enabled = taskTimer.Status != TimerStatus.Stopped;

            //change text for timer buttons
            if (taskTimer.Status == TimerStatus.Paused)
            {
                btnPause.Text = Strings.Resume;
                pauseTimerToolStripMenuItem.Text = Strings.ResumeTimer;
            }
            else
            {
                btnPause.Text = Strings.Pause;
                pauseTimerToolStripMenuItem.Text = Strings.PauseTimer;
            }
            var tsk = cbTask.SelectedItem as Task;

            if (tsk != null)
                if (tsk.BillingType.HasValue && tsk.BillingType.Value != 1)
                {
                    cbBillable.Checked = true;
                    cbBillable.Enabled = true;
                }
                else
                {
                    cbBillable.Enabled = false;
                    cbBillable.Checked = false;
                }
        }

        /// <summary>
        /// Set form position in reght botton corner
        /// </summary>
        private void SetPosition()
        {
            Left = (Screen.PrimaryScreen.WorkingArea.Width - Width);
            Top = (Screen.PrimaryScreen.WorkingArea.Height - Height);
        }

        /// <summary>
        /// Shows the content of the main.
        /// </summary>
        private void ShowMainContent()
        {
            try
            {
                // use invoker to prevent exceptions
                Invoke(new MethodInvoker(InvokeUpdateMainContent));
            }
            catch
            {
            }
        }

        /// <summary>
        /// Changes the main content visibility.
        /// </summary>
        /// <param name="visible">if set to <c>true</c> [visible].</param>
        private void ChangeMainContentVisibility(bool visible)
        {
            pnlMain.Visible = visible;
            pnlUpdate.Visible = !visible;
        }
        /// <summary>
        /// Invokes the content of the update main.
        /// </summary>
        private void InvokeUpdateMainContent()
        {
            pnlMain.Visible = true;
            pnlUpdate.Visible = false;

            //store prevous selected data.
            Project project = cbProject.SelectedItem as Project;
            Task task = cbTask.SelectedItem as Task;

            cbProject.Items.Clear();
            cbTask.Items.Clear();

            // fill projects list
            foreach (Project o in ObjectsHelper.Instance.Projects)
                cbProject.Items.Add(o);
            try
            {
                //set prevous value and fill tasks list.
                cbProject.SelectedItem = project;
                CreateTaskItems();
                cbTask.SelectedItem = task;
            }
            catch //do nothing
            {
            }
            if ((cbProject.Items.Count > 0) && (cbProject.SelectedIndex == -1)) // select first project and create tasks list
            {
                cbProject.SelectedIndex = 0;
                CreateTaskItems();
            }
        }

        /// <summary>
        /// Hide application splash
        /// </summary>
        private void InvokeHideSplash()
        {
            splashForm.IsNeedClose = true;
            splashForm.Close();
            splashForm = null;
        }

        /// <summary>
        /// Hides the application splash screen.
        /// </summary>
        public void HideApplicationSplashScreen()
        {
            try
            {
                if (splashForm != null)
                {
                    //use method invoker to prevent exceptions when we use control from another thread
                    splashForm.Invoke(new MethodInvoker(InvokeHideSplash));
                }
            }
            catch
            {
            }
        }
        #endregion

        #region Validate
        /// <summary>
        /// Validate user inputs. Show alerts if need.
        /// </summary>
        /// <param name="showAlerts">If true show alert.</param>
        /// <returns>Return true if input is valid.</returns>
        private bool ValidateInput(bool showAlerts)
        {
            if (cbProject.SelectedItem == null)//Project doesn't selected
            {
                if (showAlerts)
                    errorProvider1.SetError(cbProject, Strings.SelectProject);
                return false;
            }
            if (cbTask.SelectedItem == null)//task doesn't selected
            {
                if (showAlerts)
                    errorProvider1.SetError(cbTask, Strings.SelectTask);
                return false;
            }
            if (String.IsNullOrEmpty(tbHours.Text.Trim())) //Hours dosen't filled
            {
                if (showAlerts)
                    errorProvider1.SetError(cbTask, Strings.EnterHours);
                return false;
            }
            try
            {
                float.Parse(tbHours.Text);
            }
            catch (FormatException)//User enter hours in invalid format
            {
                if (showAlerts)
                    errorProvider1.SetError(tbHours, Strings.EnterInValidFormat);
                return false;
            }
            catch (Exception ex)//User enter hours and it can not be converted
            {
                if (showAlerts)
                    errorProvider1.SetError(tbHours, ex.Message);
                return false;
            }

            return true;
        }
        #endregion
    }
}